﻿/// <reference path="../jquery-1.4.4.js" />
/// <reference path="../jquery-1.4.4-vsdoc.js" />

/*!  
** Copyright (c) 2011 Ray Liang (http://www.dotnetage.com)
** Dual licensed under the MIT and GPL licenses:
** http://www.opensource.org/licenses/mit-license.php
** http://www.gnu.org/licenses/gpl.html
** 
**----------------------------------------------------------------
** title        : DJME ListBox
** version   : 2.0.2
** modified: 2010-3-1
** depends:
**    jquery.ui.core.js
**    jquery.ui.widget.js
**    jquery.ui.mouse.js
**    jquery.ui.draggable.js
**    jquery.ui.droppable.js
**    jquery.ui.sortable.js 
**    jquery.tmpl.js
**----------------------------------------------------------------
*/

(function ($) {
    $.widget("ui.listbox", {
        options: {
            selected: null,
            edited: null,
            deleted: null,
            changed: null, //triggered when position is changed
            scrollEnd: null,
            droptargets: null,
            dropped: null,
            dropover: null,
            dropout: null,
            itemsloaded: null,
            itemclass: null,
            itemhoverclass: null,
            itemselectedclass: null,
            multiselection: false,
            inline: false,
            dataTextField: ".d-list-item-text",
            dataValueField: "input[type='hidden']",
            checkboxs: false,
            editable: false,
            sortable: false,
            droppable: false,
            selectedItem: null,
            selectedValue: null
        },
        _create: function () {
            var self = this, opts = this.options, el = this.element, eventPrefix = this.widgetEventPrefix;

            if (opts.selected) el.bind(eventPrefix + "selected", opts.selected);
            if (opts.edited) el.bind(eventPrefix + "edited", opts.edited);
            if (opts.deleted) el.bind(eventPrefix + "deleted", opts.deleted);
            if (opts.dropout) el.bind(eventPrefix + "dropout", opts.dropout);
            if (opts.dropover) el.bind(eventPrefix + "dropover", opts.dropover);
            if (opts.dropped) el.bind(eventPrefix + "dropped", opts.dropped);
            if (opts.changed) el.bind(eventPrefix + "changed", opts.changed);
            if (opts.scrollEnd) el.bind(eventPrefix + "scrollEnd", opts.scrollEnd);
            if (opts.itemsloaded) el.bind(eventPrefix + "itemsloaded", opts.itemsloaded);
            el.addClass("d-listbox");

            var $ul = el.children("ul");
            self._initDataContainer($ul);

            el.bind("scroll", function () {
                if (opts.inline) {
                    if (($ul.width() - el.scrollLeft()) <= el.width())
                        self._triggerEvent("scrollEnd", self);
                }
                else {
                    var st = el.scrollTop(),
                            ph = el.height(),
                            ch = $ul.height();

                    if ((ch - st) <= ph) {
                        self._triggerEvent("scrollEnd", self);
                    }
                }
            });

            if (!self.options.checkboxs)
                self._initSelection();
        },
        _initSelection: function () {
            var valElement = $(".d-listbox-values", this.element);
            this.options.selectedValue = valElement.val();
            if (valElement.val()) {
                var items = this.element.find(".d-list-item");
                if (this.options.multiselection) {
                    var vals = valElement.val().split(",");
                    $.each(vals, function (i, v) {
                        var _sel = items.find("input[value='" + v + "']");
                        if (_sel.length) _sel.closest(".d-list-item").addClass("d-list-item-selected");
                    });
                }
                else {
                    var _sel = items.find("input[value='" + valElement.val() + "']");
                    if (_sel.length) _sel.closest(".d-list-item").addClass("d-list-item-selected");
                }
            }
        },
        _contains: function (parent, child) {
            try {
                return $.contains(parent, child);
            } catch (e) {
                return false;
            }
        },
        _initDataContainer: function ($ul) {
            var self = this, opts = this.options, el = this.element;
            if ($ul.length) {
                $ul.addClass("d-list-items-holder")
                     .children().not("d-list-item-disabled").each(function (i, n) {
                         self._initItem(n);
                     });
            }
            else {
                $("<ul/>").addClass("d-list-items-holder").appendTo(el);
            }

            if (this.options.sortable) {
                $ul.sortable({
                    forceHelperSize: true,
                    forcePlaceholderSize: true,
                    placeholder: "d-list-item-placeholder",
                    items: ".d-list-item",
                    update: function (event, ui) {
                        var seq = $ul.find(".d-list-item").index(ui.item);
                        self._triggerEvent("changed", { "item": ui.item, "index": seq });
                    },
                    cancel: ".d-list-item-disabled"
                })

                if (this.options.droptargets)
                    $ul.sortable("option", "connectWith", this.options.droptargets);
            }

            if (this.options.inline) {
                var _items = $ul.find(".d-list-item:visible");
                var _w = 0;
                _items.each(function (i, n) {
                    _w += $(n).outerWidth(true);
                });

                if (_w) {
                    $ul.width(_w);
                    el.css({ "overflow-y": "hidden" });
                }
            }

            if (this.options.droppable) {
                $ul.droppable({
                    greedy: true,
                    over: function (event, ui) {
                        self._triggerEvent("dropout", { "listbox": self, item: ui.draggable, container: $(this) });
                    },
                    out: function (event, ui) {
                        self._triggerEvent("dropover", { "listbox": self, item: ui.draggable, container: $(this) });
                    },
                    drop: function (event, ui) {
                        if (self._contains(this, ui.draggable.get(0)))
                            return;
                        self._triggerEvent("dropped", { "listbox": self, item: ui.draggable, container: $(this) });
                    }
                });
            }
        },
        itemReset: function (element) {
            this._initItem(element); 
         },
        _initItem: function (element) {
            var $li = $(element), self = this;
            $li.addClass("d-list-item")
               .bind("click", this._delegate(this, this._onitemclick))
               .bind("mouseenter", function () { $(this).addClass("d-list-item-hover"); })
               .bind("mouseleave", function () { $(this).removeClass("d-list-item-hover"); });

            if (this.options.checkboxs) {
                var _checkbox = $("<input type='checkbox' />").addClass("d-list-item-checkbox").prependTo($li),
                _valItem = _checkbox.closest(".d-list-item").find(this.options.dataValueField),
                _val = $(this.element).children(".d-listbox-values");

                if (_val.val()) {
                    _values = _val.val().split(",");
                    if ($.inArray(_valItem.val(), _values) > -1)
                        _checkbox.attr("checked", true);
                }

                _checkbox.click(function () { self._updateCheckedValues(); });
            }

            if ((this.options.editable) && ($.fn.editable)) {
                var $txt = $li.find(this.options.dataTextField);
                if ($txt.length) {
                    $txt.editable({ submit: function (_val) {
                        self._triggerEvent("edited", { "item": element, "text": _val });
                    }
                    });
                }
            } else $li.disableSelection();
        },
        _delegate: function (context, handler) {
            return function (e) {
                handler.apply(context, [e, this]);
            };
        },
        _triggerEvent: function (eventName, eventArgs) {
            this.element.trigger(this.widgetEventPrefix + eventName, eventArgs);
        },
        _onitemclick: function (e, element) {
            var $li = $(element);
            var _value = $(">.d-listbox-values", this.element);

            if (this.options.multiselection) {
                $li.toggleClass("d-list-item-selected");

                if (!this.options.checkboxs) {
                    if ((this.options.dataValueField) && (_value.length)) {
                        var $lis = $(".d-list-item-selected", element);
                        if ($lis.length) {
                            var selectedValues = new Array();
                            $lis.each(function (i, n) {
                                var $item = $(n);
                                var _v = $item.find(this.options.dataValueField);
                                if (_v.length) {
                                    if (_v.get(0).tagName == "INPUT")
                                        selectedValues.push(_v.val());
                                    else
                                        selectedValues.push(_v.text());
                                }
                            });

                            if (selectedValues.length) _value.val(selectedValues.join(","));
                            else _value.val("");
                        } // end $lis.length
                        else { _value.val(""); }
                    } // end dataValueField and _value.length
                } //end checkbox
            }
            else {
                $li.siblings(".d-list-item-selected").removeClass("d-list-item-selected");
                $li.addClass("d-list-item-selected");

                if (!this.options.checkboxs) {
                    if ((this.options.dataValueField) && (_value.length)) {
                        var _vf = $li.find(this.options.dataValueField);
                        if (_vf.length) {
                            if (_vf.get(0).tagName == "INPUT")
                                _value.val(_vf.val());
                            else
                                _value.val(_vf.text);
                        }
                    }
                    else
                        _value.val($li.text());
                }
            }

            this.options.selectedItem = element;
            this.options.selectedValue = _value.val();
            var _eventArgs = { item: element, value: _value.val(), data: null };
            if ($.tmpl) {
                var tmplElement = $.tmplItem(element);
                if (tmplElement) {
                    if (tmplElement.data)
                        _eventArgs.data = tmplElement.data;
                }
            }
            this._triggerEvent("selected", _eventArgs);
        },
        _updateCheckedValues: function () {
            var _checkboxs = $(this.element).find(".d-list-item-checkbox"), self = this,
            _val = $(this.element).children(".d-listbox-values"), _selValues = new Array();

            _checkboxs.each(function (i, n) {
                var _checkbox = $(n);
                if (_checkbox.attr("checked")) {
                    var $item = _checkbox.closest(".d-list-item"),
                     _v = $item.find(self.options.dataValueField);
                    if (_v.length) {
                        if (_v.get(0).tagName == "INPUT")
                            _selValues.push(_v.val());
                        else
                            _selValues.push(_v.text());
                    }
                }
            });

            if (_selValues.length)
                _val.val(_selValues.join(","));
            else
                _val.val("");
        },
        getSelected: function () {
        },
        add: function (content) {
            var _content = content,
            $tmp = $(content);

            if ($tmp.length) {
                if ($tmp.get(0) == "LI")
                    _content = $tmp.html();
            }

            var $li = $("<li/>").html(_content)
                        .appendTo($(".d-list-items-holder", this.element));
            this._initItem($li);
        },
        del: function ($li) {
        },
        _showLoader: function () {
            var _loader = $("<div/>").addClass("d-loader").appendTo(this.element), el = this.element;
            _loader.css({
                height: el.height() + "px",
                width: el.width() + "px",
                "left": el.position().left + "px",
                "top": el.position().top + "px"
            });
            return _loader;
        },
        _hideLoader: function () {
            var loader = $(".d-loader", this.element);
            if (loader.length) loader.remove();
        },
        load: function (_url, _routeData, _replaceExists, httpMethod) {
            var self = this, el = this.element;
            $.ajax({
                type: httpMethod ? httpMethod : "POST",
                url: _url,
                data: _routeData,
                beforeSend: function () {
                    self._showLoader();
                },
                success: function (data) {
                    if (data) {
                        var $d = $(data);
                        if ($d.length()) {

                            if (_replaceExists) {
                                if ($d.get(0).tagName == "UL")
                                    el.empty();
                                $d.appendTo(el);
                                self._initDataContainer($d);
                            }
                            else {
                                var $items = null,
                                 $ul = el.children("d-list-items-holder");
                                if ($d.get(0).tagName == "UL")
                                    $items = $(">li", $d);
                                else
                                    $items = $d;
                                $ul.append($d);
                                $items.each(function (i, n) {
                                    self._initItem($(n));
                                });
                            }
                        }

                        if (self.options.inline) {
                            var _items = el.children("ul").find(".d-list-item:visible"), _w = 0;
                            _items.each(function (i, n) {
                                _w += $(n).outerWidth(true);
                            });

                            if (_w) {
                                el.children("ul").width(_w);
                                el.css({ "overflow-y": "hidden" });
                            }
                        }

                    }
                    self._triggerEvent("itemsloaded", self);
                    self._hideLoader();
                }
            });
        },
        loadData: function (_url, _routeData) {
            $ul = $(">.d-list-items-holder", this.element);
            $ul.empty();
            this.loadJson(_url, _routeData, this.element.attr("id") + "_tmpl");
        },
        loadJson: function (_url, _routeData, tmplID, callBack, httpMethod) {
            var self = this;
            $.ajax({
                type: httpMethod ? httpMethod : "POST",
                url: _url,
                dataType: "json",
                data: _routeData,
                beforeSend: function () {
                    self._showLoader();
                },
                success: function (data) {
                    self.dataBind(data.Model, tmplID);
                    self._triggerEvent("itemsloaded", self);
                    self._hideLoader();
                    if ($.isFunction(callBack)) callBack(self, data);
                }
            });
        },
        dataBind: function (data, tmplID) {
            var self = this;
            if ((data) && (data.length) && (tmplID) && ($.tmpl)) {
                $ul = $(">.d-list-items-holder", self.element);
                var __tmpl = $("#" + tmplID);
                if (__tmpl.length == 0) return;
                __tmpl.tmpl(data).appendTo($ul);
                var $items = $("li:not(.d-list-item)", $ul);
                $items.each(function (i, n) {
                    self._initItem($(n));
                });

                if (self.options.inline) {
                    var _items = $ul.find(".d-list-item:visible"), _w = 0;
                    _items.each(function (i, n) {
                        _w += $(n).outerWidth(true);
                    });
                    if (_w) {
                        $ul.width(_w);
                        self.element.css({ "overflow-y": "hidden" });
                    }
                }
            }
        },
        select: function (_val) {
            var $items = $(">.d-list-items-holder>.d-list-item", this.element).find(this.options.dataValueField);
            $items.each(function (i, n) {
                if ($(n).val() == _val) {
                    $(n).click();
                    return false;
                }
            });
        },
        destroy: function () {
            $.Widget.prototype.destroy.call(this);
        }
    });
})(jQuery);   